#include "gwavi.h"
#include <QImage>
#include <QFile>
#include <QBuffer>
#include <QDebug>

GWAVI::GWAVI()
{
    mFileIO = new FileIO;
    utils = new AviUtils;
}

void GWAVI::AddImages(QString filename,QList<QImage> lstImage)
{
    if(lstImage.count() == 0)
        return;

    QString fourcc= "DIB ";
    quint32 width = lstImage.at(0).width();
    quint32 height = lstImage.at(0).height();

    quint32 fps = 1;
    gwavi_t* gwavi = gwavi_open(width,height,fourcc,fps,lstImage.count(),0,0,24);

    for(int i =0;i<lstImage.count();i++)
    {
        QByteArray arr;
        QBuffer buffer(&arr);
        buffer.open(QIODevice::ReadWrite);

        QImage curImg = lstImage.at(i);
        curImg.save(&buffer,"JPEG");

        int length = arr.length();

        //qDebug()<<length;
        gwavi_add_frame(gwavi,(const uchar*)buffer.data().data(),length);
        buffer.close();
    }

    gwavi_close(gwavi);

    QFile f(filename);
    f.open(QIODevice::WriteOnly);
    QDataStream datasteam(&f);
    datasteam.writeRawData(gwavi->out->data(),gwavi->out->length());
    f.close(); 

}
gwavi_t* GWAVI::gwavi_open(quint32 width, quint32 height, QString fourcc, quint32 fps,quint32 frameCount,quint32 dotsPerMeterX,quint32 dotsPerMeterY,quint32 bitsPerPixel)
{
    if(fps<1)
        return nullptr;

    int numColorBits = bitsPerPixel /8;
    gwavi_t *gwavi = new gwavi_t;
    gwavi->out = new QByteArray;
    gwavi->avi_header.time_delay = 200;
    gwavi->avi_header.data_rate = width * height * numColorBits;
    gwavi->avi_header.reserved = 0;
    gwavi->avi_header.flags = 0x0810;
    gwavi->avi_header.data_streams = 1;
    gwavi->avi_header.number_of_frames = frameCount;
    gwavi->avi_header.initial_frames = 0;
    gwavi->avi_header.height = height;
    gwavi->avi_header.width = width;
    gwavi->avi_header.buffer_size = width * height * numColorBits;
    gwavi->avi_header.playback_data_rate = 0;
    gwavi->avi_header.time_scale = 1;
    gwavi->avi_header.starting_time = 0;
    gwavi->avi_header.data_length = 0;

    gwavi->stream_header_v.data_type = "vids";
    gwavi->stream_header_v.codec =fourcc;//fourcc;
    gwavi->stream_header_v.flags = 0;
    gwavi->stream_header_v.priority = 0;
    gwavi->stream_header_v.language = 0;
    gwavi->stream_header_v.initial_frames = 0;
    gwavi->stream_header_v.data_rate = fps;
    gwavi->stream_header_v.start_time = 0;
    gwavi->stream_header_v.data_length = frameCount;
    gwavi->stream_header_v.time_scale = 1;
    gwavi->stream_header_v.buffer_size = width * height * numColorBits;
    gwavi->stream_header_v.sample_size = 0;
    gwavi->stream_header_v.quality = 0;


    gwavi->stream_header_v.left = 0;
    gwavi->stream_header_v.top = 0;
    gwavi->stream_header_v.right = (quint16)width;
    gwavi->stream_header_v.bottom = (quint16)height;

    gwavi->stream_format_v.header_size = 40;
    gwavi->stream_format_v.width = width;
    gwavi->stream_format_v.height = height;
    gwavi->stream_format_v.num_planes = 1;
    gwavi->stream_format_v.bits_per_pixel = bitsPerPixel;
    gwavi->stream_format_v.compression_type ="MJPG";
    gwavi->stream_format_v.image_size =0;
    gwavi->stream_format_v.colors_used = 0;
    gwavi->stream_format_v.colors_important = 0;
    gwavi->stream_format_v.x_pels_per_meter = dotsPerMeterX;
    gwavi->stream_format_v.y_pels_per_meter = dotsPerMeterY;
    gwavi->stream_format_v.palette = 0;
    gwavi->stream_format_v.palette_count = 0;


    mFileIO->write_chars_bin(gwavi->out,"RIFF",4);
    mFileIO->write_chars_bin(gwavi->out,"AVI ",4);

    utils->write_avi_header_chunk(gwavi);

    mFileIO->write_chars_bin(gwavi->out,"LIST",4);

    gwavi->marker = gwavi->out->length();
    mFileIO->write_chars_bin( gwavi->out,"movi",4);

    return gwavi;
}

int GWAVI::gwavi_add_frame(gwavi_t *gwavi,const uchar* buffer, size_t len)
{
    size_t maxi_pad;
    size_t t;

    if (!gwavi || !buffer)
    {
        return -1;
    }

    if(len < 256)
    {
        return -1;
    }

    maxi_pad = len % 4;
    if (maxi_pad > 0)
    {
        maxi_pad = 4 - maxi_pad;
    }

    t = gwavi->out->length();
    gwavi->lstStart.append((quint32)(t-gwavi->marker));

    mFileIO->write_chars_bin(gwavi->out,"00dc",4);
    mFileIO->write_int(gwavi->out,(quint32)(len + maxi_pad));

    gwavi->out->append((char*)buffer,len);
    gwavi->out->append(maxi_pad,'0');

    gwavi->lstLen.append((quint32)(len + maxi_pad));

    return 0;
}

int GWAVI::gwavi_close(gwavi_t *gwavi)
{
    long t;
    if(!gwavi)
    {
        return -1;
    }

    t= gwavi->out->length();
    mFileIO->insert_int(gwavi->out,gwavi->marker,(quint32)(t-gwavi->marker));

    mFileIO->write_chars_bin(gwavi->out,"idx1",4);

    uint marker = gwavi->out->length();
    for(uint i=0;i<gwavi->lstLen.count();i++)
    {
        mFileIO->write_chars_bin(gwavi->out,"00dc",4);
        mFileIO->write_int(gwavi->out,quint32(16));
        mFileIO->write_int(gwavi->out,quint32(gwavi->lstStart.at(i)));
        mFileIO->write_int(gwavi->out,quint32(gwavi->lstLen.at(i)));
    }

    t= gwavi->out->length();
    mFileIO->insert_int(gwavi->out,marker,(quint32)(t-marker));

    t= gwavi->out->length();
    mFileIO->insert_int(gwavi->out,4,(quint32)(t-4));
    return 0;
}
